/**
 * 
 */
package hanto.studentdlally.common;

import hanto.util.HantoCoordinate;
import hanto.util.HantoPieceType;
import hanto.util.HantoPlayerColor;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Doug
 * @version 1
 *
 */
public class HantoBoard {
	private final List<HantoPiece> playedPieces;

	public HantoBoard(){
		playedPieces = new ArrayList<HantoPiece>();
	}

	/**
	 * Plays a piece
	 * @param h the piece to play
	 */
	public void playPiece(HantoPiece h){
		playedPieces.add(h);
	}

	/**
	 * Moves a piece from a specified location to a specified location
	 * @param from source coordinate
	 * @param to destination coordinate
	 */
	public void movePiece(HantoCoordinate from, HantoCoordinate to){
		final HantoPiece hp = getPieceByCoordinates(from);
		playedPieces.add(new HantoPiece(hp.getColor(), hp.getType(), to));
		playedPieces.remove(hp);
	}

	/**
	 * @param coord coordinate to find the piece at
	 * @return the piece, null if it cannot be found
	 */
	public HantoPiece getPieceByCoordinates(HantoCoordinate coord) {
		if(coord == null){
			return null;
		}
		HantoPiece piece = null;
		for(HantoPiece i : playedPieces){
			if(i.getCoordinate().getX() == coord.getX() && i.getCoordinate().getY() == coord.getY()){
				piece = i;
				break;
			}
		}
		return piece;
	}

	/**
	 * Checks if a piece is surrounded
	 * @param hp piece to check for surrounded-ness
	 * @return true if surrounded, false otherwise
	 */
	public boolean isSurrounded(HantoPiece hp){
		if(hp == null){
			return false;
		}
		final HantoCoordinate coord = hp.getCoordinate();
		//Check above
		if(getPieceByCoordinates(new Coordinate(coord.getX(), coord.getY() + 1)) == null){
			return false;
		}

		//Check above and to the right
		if(getPieceByCoordinates(new Coordinate(coord.getX() + 1, coord.getY())) == null){
			return false;
		}

		//Check below and to the right
		if(getPieceByCoordinates(new Coordinate(coord.getX() + 1, coord.getY() - 1)) == null){
			return false;
		}

		//Check below
		if(getPieceByCoordinates(new Coordinate(coord.getX(), coord.getY() - 1)) == null){
			return false;
		}

		// Check below and to the left
		if(getPieceByCoordinates(new Coordinate(coord.getX() - 1, coord.getY())) == null){
			return false;
		}

		// Check above and to the left
		if(getPieceByCoordinates(new Coordinate(coord.getX() - 1, coord.getY() + 1)) == null){
			return false;
		}

		return true;
	}

	/**
	 * Checks the current board to see if all the pieces are connected
	 * @return true if all pieces are connected, false otherwise
	 */
	public boolean isConnected(){
		final List<HantoPiece> discovered = new ArrayList<HantoPiece>();
		discoverPieces(discovered, playedPieces.get(0).getCoordinate());
		return (discovered.size() == playedPieces.size());
	}

	/**
	 * Accumulator function to discover connected pieces
	 * @param discovered an empty arraylist to keep track of the pieces discovered thus far
	 */
	private void discoverPieces(List<HantoPiece> discovered, HantoCoordinate start) {
		final HantoPiece hp = getPieceByCoordinates(start);
		if(hp == null || discovered.contains(hp)){
			return;
		}
		else{
			discovered.add(hp);
			// Now try all of the neighbors
			discoverPieces(discovered, new Coordinate(hp.getCoordinate().getX(), hp.getCoordinate().getY() + 1));
			discoverPieces(discovered, new Coordinate(hp.getCoordinate().getX() + 1, hp.getCoordinate().getY()));
			discoverPieces(discovered, new Coordinate(hp.getCoordinate().getX() + 1, hp.getCoordinate().getY() - 1));
			discoverPieces(discovered, new Coordinate(hp.getCoordinate().getX(), hp.getCoordinate().getY() - 1));
			discoverPieces(discovered, new Coordinate(hp.getCoordinate().getX() - 1, hp.getCoordinate().getY()));
			discoverPieces(discovered, new Coordinate(hp.getCoordinate().getX() - 1, hp.getCoordinate().getY() + 1));
		}

	}

	/**
	 * Prints out the board
	 * @return the board, represented as a string
	 */
	public String getPrintableBoard(){
		String out = "";
		for(HantoPiece i : playedPieces){
			out = out + i.getColor().toString() + " " + i.getType().toString() + " at (" + i.getCoordinate().getX() + "," + i.getCoordinate().getY() + ")\n";
		}
		return out;
	}

	/**
	 * Finds the blue butterfly
	 * @return the blue butterfly, null if it is not on the board
	 */
	public HantoPiece findBlueButterfly() {
		HantoPiece bb = null;
		for(HantoPiece i : playedPieces){
			if(i.getColor() == HantoPlayerColor.BLUE && i.getType() == HantoPieceType.BUTTERFLY){
				bb = i;
				break;
			}
		}
		return bb;
	}

	/**
	 * Finds the red butterfly
	 * @return the red butterfly, null if it is not on the board
	 */
	public HantoPiece findRedButterfly() {
		HantoPiece rb = null;
		for(HantoPiece i : playedPieces){
			if(i.getColor() == HantoPlayerColor.RED && i.getType() == HantoPieceType.BUTTERFLY){
				rb = i;
				break;
			}
		}
		return rb;
	}

	/**
	 * Checks if the provided coordinate is adjacent to any played piece
	 * @param coord the coordinate to check
	 * @return true if it is adjacent, false otherwise
	 */
	public boolean isAdjacentToAny(HantoCoordinate coord) {
		for(HantoPiece p : playedPieces){
			if(Coordinate.generateCoordinate(p.getCoordinate()).isAdjacent(coord)){
				return true;
			}
		}
		//Otherwise...
		return false;
	}

	/** Finds all the pieces of a specified color
	 * @param myColor find all the pieces of this color
	 * @return an ArrayList containing all the HantoPieces of the specified color
	 */
	public List<HantoPiece> getAllPieces(HantoPlayerColor myColor){
		final List<HantoPiece> pieces = new ArrayList<HantoPiece>();
		for(HantoPiece p : playedPieces){
			if(p.getColor() == myColor){
				pieces.add(p);
			}
		}
		return pieces;
	}

	/** Getter for the list of pieces
	 * @return all the pieces that have been played
	 */
	public List<HantoPiece> getAllPieces(){
		return playedPieces;
	}

	/** Checks if the coordinates are adjacent to a piece of the specified color
	 * @param color color to check
	 * @param coord coord to check
	 * @return true if adjacent, false otherwise
	 */
	public boolean isAdjacentToAny(HantoPlayerColor color, HantoCoordinate coord) {
		for(HantoPiece p : playedPieces){
			if(p.getColor() == color){
				if(Coordinate.generateCoordinate(p.getCoordinate()).isAdjacent(coord)){
					//System.out.println("(" + coord.getX() + ", " + coord.getY() +") is adj to (" + p.getCoordinate().getX() + ", " + p.getCoordinate().getY() + ")");
					return true;
				}
			}
		}
		//System.out.println("lol");
		return false;
	}
}


